/*
** $ 身份：嘞操作码.h $
** 炉啊虚拟机器的操作码
** 请参见 炉啊.h中的版权声明
*
* 本人所用声母表: a啊 b哔 c西 d迪 e鹅 f弗 g哥 
* h喝 i艾 j鸡 k颗 l嘞 m摸 n恩
* o欧 p匹 q气 r日 s丝 t嚏 
* u由 v微 w屋 x斯 y医 z只
*
* 一些英文单词缩写,我的翻译大多来自;有道词典,谷歌翻译,百度.
* 一些术语实在不好翻译,所以就原封不动.
* 
* 一些特有的表示特有库的术语是无法翻译的 *
* 否则编译器不能识别不能通过,第一版汉化就行不通.
* 
*/

#ifndef 嘞操作码_喝
#define 嘞操作码_喝

#include "嘞极限.h"

/*===========================================================================
  我们假设指令是无符号32位整数.
  所有指令的前7位都有一个操作码.
  指令可以有以下格式:

            3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
            1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
艾甲乙丙         丙(8)     |     乙(8)    |颗|   甲(8)       |  操作(7)     |
艾甲乙斯              乙斯(17)               |   甲(8)       |  操作(7)     |
艾甲丝乙斯          丝乙斯(有符号)(17)       |   甲(8)       |  操作(7)     |
艾甲斯                          甲斯(25)                     |  操作(7)     |
艾丝跳                          丝跳(25)                     |  操作(7)     |

  带符号的参数表示为多余的 K颗(常量) : 
  表示的值是无符号的值减去 K颗(常量) , 
  K颗(常量) 是对应的无符号参数最大值的一半.
  这里大写的 ABC 翻译为 甲乙丙 .
===========================================================================*/

enum 操作模式 {艾甲乙丙, 艾甲乙斯, 艾甲丝乙斯, 艾甲斯, 艾丝跳};  /* 基本指令格式 */


/*
** 操作码参数的大小和位置.
* iABC,     iABx,     iAsBx,      iAx,    isJ
* 艾甲乙丙, 艾甲乙斯, 艾甲丝乙斯, 艾甲斯, 艾丝跳
*/
#define 大小_丙		    8
#define 大小_乙		    8
#define 大小_乙斯		(大小_丙 + 大小_乙 + 1)
#define 大小_甲		    8
#define 大小_甲斯		(大小_乙斯 + 大小_甲)
#define 大小_丝跳		(大小_乙斯 + 大小_甲)

#define 大小_操作		7

#define 销售点_操作		0

#define 销售点_甲		(销售点_操作 + 大小_操作)
#define 销售点_颗		(销售点_甲 + 大小_甲)
#define 销售点_乙		(销售点_颗 + 1)
#define 销售点_丙		(销售点_乙 + 大小_乙)

#define 销售点_乙斯		销售点_颗

#define 销售点_甲斯		销售点_甲

#define 销售点_丝跳		销售点_甲

/*
** 操作码参数的限制.
** 我们使用 (有符号) '整型' 操纵大多数参数,
** 所以它们必须符合 整型.
*/

/* 检查类型 '整型' 是否至少有 '哔' 位 ('哔' < 32) */
#define 嘞_整型有无哔位(哔)		((无符整型_最大 >> ((哔) - 1)) >= 1)

#if 嘞_整型有无哔位(大小_乙斯)
#define 最大参_乙斯	((1<<大小_乙斯)-1)
#else
#define 最大参_乙斯	最大_整型
#endif

#define 偏移_丝乙斯	(最大参_乙斯>>1)         /* '丝乙斯' 是有符号的 */

#if 嘞_整型有无哔位(大小_甲斯)
#define 最大参_甲斯	((1<<大小_甲斯)-1)
#else
#define 最大参_甲斯	最大_整型
#endif

#if 嘞_整型有无哔位(大小_丝跳)
#define 最大参_丝跳	((1 << 大小_丝跳) - 1)
#else
#define 最大参_丝跳	最大_整型
#endif

#define 偏移_丝跳	(最大参_丝跳 >> 1)


#define 最大参_甲	((1<<大小_甲)-1)
#define 最大参_乙	((1<<大小_乙)-1)
#define 最大参_丙	((1<<大小_丙)-1)
#define 偏移_丝丙	(最大参_丙 >> 1)

#define 整型到丝丙(艾)	((艾) + 偏移_丝丙)
#define 丝丙到整型(艾)	((艾) - 偏移_丝丙)

/* 在 '匹' 位置创建一个具有 '恩' 1位的掩码 */
#define 口罩1(恩,匹)	((~((~(指令)0)<<(恩)))<<(匹))

/* 在位置 '匹'  处创建一个具有 '恩'  个0位的掩码 */
#define 口罩0(恩,匹)	(~口罩1(恩,匹))

/*
** 以下宏有助于操纵指令
*/
#define 取_操作码(艾)	(投(操作码, ((艾)>>销售点_操作) & 口罩1(大小_操作,0)))
#define 设置_操作码(艾,欧)	((艾) = (((艾)&口罩0(大小_操作,销售点_操作)) | \
		((投(指令, 欧)<<销售点_操作)&口罩1(大小_操作,销售点_操作))))

#define 检查操作摸(艾,摸)	(取操作模式(取_操作码(艾)) == 摸)


#define 取实参(艾,销售点,大小)	(投_整型(((艾)>>(销售点)) & 口罩1(大小,0)))
#define 设置实参(艾,微,销售点,大小)	((艾) = (((艾)&口罩0(大小,销售点)) | \
                ((投(指令, 微)<<销售点)&口罩1(大小,销售点))))

#define 取实参_甲(艾)	取实参(艾, 销售点_甲, 大小_甲)
#define 设置实参_甲(艾,微)	设置实参(艾, 微, 销售点_甲, 大小_甲)

#define 取实参_乙(艾)	检查_表达式(检查操作摸(艾, 艾甲乙丙), 取实参(艾, 销售点_乙, 大小_乙))
#define 取实参_丝乙(艾)	丝丙到整型(取实参_乙(艾))
#define 设置实参_乙(艾,微)	设置实参(艾, 微, 销售点_乙, 大小_乙)

#define 取实参_丙(艾)	检查_表达式(检查操作摸(艾, 艾甲乙丙), 取实参(艾, 销售点_丙, 大小_丙))
#define 取实参_丝丙(艾)	丝丙到整型(取实参_丙(艾))
#define 设置实参_丙(艾,微)	设置实参(艾, 微, 销售点_丙, 大小_丙)

#define 测试实参_颗(艾)	检查_表达式(检查操作摸(艾, 艾甲乙丙), (投_整型(((艾) & (1u << 销售点_颗)))))
#define 取实参_颗(艾)	检查_表达式(检查操作摸(艾, 艾甲乙丙), 取实参(艾, 销售点_颗, 1))
#define 设置实参_颗(艾,微)	设置实参(艾, 微, 销售点_颗, 1)

#define 取实参_乙斯(艾)	检查_表达式(检查操作摸(艾, 艾甲乙斯), 取实参(艾, 销售点_乙斯, 大小_乙斯))
#define 设置实参_乙斯(艾,微)	设置实参(艾, 微, 销售点_乙斯, 大小_乙斯)

#define 取实参_甲斯(艾)	检查_表达式(检查操作摸(艾, 艾甲斯), 取实参(艾, 销售点_甲斯, 大小_甲斯))
#define 设置实参_甲斯(艾,微)	设置实参(艾, 微, 销售点_甲斯, 大小_甲斯)

#define 取实参_丝乙斯(艾)  \
	检查_表达式(检查操作摸(艾, 艾甲丝乙斯), 取实参(艾, 销售点_乙斯, 大小_乙斯) - 偏移_丝乙斯)
#define 设置实参_丝乙斯(艾,哔)	设置实参_乙斯((艾),投_无符整型((哔)+偏移_丝乙斯))

#define 取实参_丝跳(艾)  \
	检查_表达式(检查操作摸(艾, 艾丝跳), 取实参(艾, 销售点_丝跳, 大小_丝跳) - 偏移_丝跳)
#define 设置实参_丝跳(艾,鸡) \
	设置实参(艾, 投_无符整型((鸡)+偏移_丝跳), 销售点_丝跳, 大小_丝跳)

#define 创建_甲乙丙颗(欧,啊,哔,西,颗)	((投(指令, 欧)<<销售点_操作) \
			| (投(指令, 啊)<<销售点_甲) \
			| (投(指令, 哔)<<销售点_乙) \
			| (投(指令, 西)<<销售点_丙) \
			| (投(指令, 颗)<<销售点_颗))

#define 创建_甲乙斯(欧,啊,哔西)	((投(指令, 欧)<<销售点_操作) \
			| (投(指令, 啊)<<销售点_甲) \
			| (投(指令, 哔西)<<销售点_乙斯))

#define 创建_甲斯(欧,啊)		((投(指令, 欧)<<销售点_操作) \
			| (投(指令, 啊)<<销售点_甲斯))

#define 创建_丝跳(欧,鸡,颗)	((投(指令, 欧) << 销售点_操作) \
			| (投(指令, 鸡) << 销售点_丝跳) \
			| (投(指令, 颗) << 销售点_颗))


#if !defined(最大索引日颗)  /* (仅用于调试) */
#define 最大索引日颗	最大实参_乙
#endif

/*
** 无效的寄存器 适合8位
*/
#define 不_寄		最大实参_甲

/*
** 日[斯] - 寄存器
** 颗[斯] - 常量 (在常量表内)
** 日颗(斯) == 若 小颗(艾) 那么 颗[斯] 否则 日[斯]
*/

/*
** 搜索正则打印行 "秩序 操作" 如果你改变这些枚举
*/
typedef enum {
/*----------------------------------------------------------------------
  名字		实参	描述
------------------------------------------------------------------------*/
操作_移,/*	甲 乙	日[甲] := 日[乙]					*/
操作_载整数,/*	甲 丝乙斯	日[甲] := 丝乙斯					*/
操作_载浮点,/*	甲 丝乙斯	日[甲] := (炉啊_号码)丝乙斯				*/
操作_载常量,/*	甲 乙斯	日[甲] := 颗[乙斯]					*/
操作_载常量斯,/*	甲	日[甲] := 颗[额外 实参]				*/
操作_载假,/*	甲	日[甲] := 假					*/
操作_嘞假跳过,/*甲	日[甲] := 假; 程序计数++				*/
操作_载真,/*	甲	日[甲] := 真					*/
操作_载无,/*	甲 乙	日[甲], 日[甲+1], ..., 日[甲+乙] := 零		*/
操作_取上值,/*	甲 乙	日[甲] := 上值[乙]				*/
操作_设置上值,/*	甲 乙	上值[乙] := 日[甲]				*/

操作_取表上,/*	甲 乙 丙	日[甲] := 上值[乙][颗[丙]:串]			*/
操作_取表,/*	甲 乙 丙	日[甲] := 日[乙][日[丙]]				*/
操作_取整数,/*	甲 乙 丙	日[甲] := 日[乙][丙]					*/
操作_取字段,/*	甲 乙 丙	日[甲] := 日[乙][颗[丙]:串]			*/

操作_设置表上,/*	甲 乙 丙	上值[甲][颗[乙]:串] := 日颗(丙)		*/
操作_设置表,/*	甲 乙 丙	日[甲][日[乙]] := 日颗(丙)				*/
操作_设置整数,/*	甲 乙 丙	日[甲][乙] := 日颗(丙)				*/
操作_设置字段,/*	甲 乙 丙	日[甲][颗[乙]:串] := 日颗(丙)			*/

操作_新表,/*	甲 乙 丙 小颗	日[甲] := {}					*/

操作_自己,/*	甲 乙 丙	日[甲+1] := 日[乙]; 日[甲] := 日[乙][日颗(丙):串]	*/

操作_加整数,/*	甲 乙 丝丙	日[甲] := 日[乙] + 丝丙				*/

操作_加常量,/*	甲 乙 丙	日[甲] := 日[乙] + 颗[丙]				*/
操作_减常量,/*	甲 乙 丙	日[甲] := 日[乙] - 颗[丙]				*/
操作_乘常量,/*	甲 乙 丙	日[甲] := 日[乙] * 颗[丙]				*/
操作_余数常量,/*	甲 乙 丙	日[甲] := 日[乙] % 颗[丙]				*/
操作_幂常量,/*	甲 乙 丙	日[甲] := 日[乙] ^ 颗[丙]				*/
操作_除常量,/*	甲 乙 丙	日[甲] := 日[乙] / 颗[丙]				*/
操作_符号除常量,/*	甲 乙 丙	日[甲] := 日[乙] // 颗[丙]				*/

操作_位与常量,/*	甲 乙 丙	日[甲] := 日[乙] & 颗[丙]:整数			*/
操作_位或常量,/*	甲 乙 丙	日[甲] := 日[乙] | 颗[丙]:整数			*/
操作_位异或常量,/*	甲 乙 丙	日[甲] := 日[乙] ~ 颗[丙]:整数			*/

操作_右移整数,/*	甲 乙 丝丙	日[甲] := 日[乙] >> 丝丙				*/
操作_左移整数,/*	甲 乙 丝丙	日[甲] := 丝丙 << 日[乙]				*/

操作_加,/*	甲 乙 丙	日[甲] := 日[乙] + 日[丙]				*/
操作_减,/*	甲 乙 丙	日[甲] := 日[乙] - 日[丙]				*/
操作_乘,/*	甲 乙 丙	日[甲] := 日[乙] * 日[丙]				*/
操作_余数,/*	甲 乙 丙	日[甲] := 日[乙] % 日[丙]				*/
操作_幂,/*	甲 乙 丙	日[甲] := 日[乙] ^ 日[丙]				*/
操作_除,/*	甲 乙 丙	日[甲] := 日[乙] / 日[丙]				*/
操作_符号除,/*	甲 乙 丙	日[甲] := 日[乙] // 日[丙]				*/

操作_位与,/*	甲 乙 丙	日[甲] := 日[乙] & 日[丙]				*/
操作_位或,/*	甲 乙 丙	日[甲] := 日[乙] | 日[丙]				*/
操作_位异或,/*	甲 乙 丙	日[甲] := 日[乙] ~ 日[丙]				*/
操作_左移,/*	甲 乙 丙	日[甲] := 日[乙] << 日[丙]				*/
操作_右移,/*	甲 乙 丙	日[甲] := 日[乙] >> 日[丙]				*/

操作_元方法索引,/*	甲 乙 丙	调用 丙 元方法 结束 日[甲] 与 日[乙]		*/
操作_元方法索引整数,/*	甲 丝乙 丙 小颗	调用 丙 元方法 结束 日[甲] 与 丝乙	*/
操作_元方法索引常量,/*	甲 乙 丙 小颗		调用 丙 元方法 结束 日[甲] 与 颗[乙]	*/

操作_负,/*	甲 乙	日[甲] := -日[乙]					*/
操作_位非,/*	甲 乙	日[甲] := ~日[乙]					*/
操作_非,/*	甲 乙	日[甲] := 非 日[乙]				*/
操作_长度,/*	甲 乙	日[甲] := 日[乙] 的长度				*/

操作_连接,/*	甲 乙	日[甲] := 日[甲].. ... ..日[甲 + 乙 - 1]		*/

操作_关闭,/*	甲	关闭全部上值 >= 日[甲]			*/
操作_待关闭,/*	甲	标记变量 甲 "待关闭"			*/
操作_跳,/*	丝跳	程序计数 += 丝跳					*/
操作_等于,/*	甲 乙 小颗	若 ((日[甲] == 日[乙]) ~= 小颗) 那么 程序计数++		*/
操作_小于,/*	甲 乙 小颗	若 ((日[甲] <  日[乙]) ~= 小颗) 那么 程序计数++		*/
操作_小等,/*	甲 乙 小颗	若 ((日[甲] <= 日[乙]) ~= 小颗) 那么 程序计数++		*/

操作_等于常量,/*	甲 乙 小颗	若 ((日[甲] == 颗[乙]) ~= 小颗) 那么 程序计数++		*/
操作_等于整数,/*	甲 丝乙 小颗	若 ((日[甲] == 丝乙) ~= 小颗) 那么 程序计数++		*/
操作_小于整数,/*	甲 丝乙 小颗	若 ((日[甲] < 丝乙) ~= 小颗) 那么 程序计数++			*/
操作_小等整数,/*	甲 丝乙 小颗	若 ((日[甲] <= 丝乙) ~= 小颗) 那么 程序计数++		*/
操作_大于整数,/*	甲 丝乙 小颗	若 ((日[甲] > 丝乙) ~= 小颗) 那么 程序计数++			*/
操作_大等整数,/*	甲 丝乙 小颗	若 ((日[甲] >= 丝乙) ~= 小颗) 那么 程序计数++		*/

操作_测试,/*	甲 小颗	若 (非 日[甲] == 小颗) 那么 程序计数++			*/
操作_测试设置,/*	甲 乙 小颗	若 (非 日[乙] == 小颗) 那么 程序计数++ 否则 日[甲] := 日[乙]	*/

操作_调用,/*	甲 乙 丙	日[甲], ... ,日[甲+丙-2] := 日[甲](日[甲+1], ... ,日[甲+乙-1]) */
操作_尾调用,/*	甲 乙 丙 小颗	返回 日[甲](日[甲+1], ... ,日[甲+乙-1])		*/

操作_返回,/*	甲 乙 丙 小颗	返回 日[甲], ... ,日[甲+乙-2]	(看笔记)	*/
操作_返回0,/*		返回						*/
操作_返回1,/*	甲	返回 日[甲]					*/

操作_为环,/*	甲 乙斯	更新计数器; 若 环继续 那么 程序计数-=乙斯; */
操作_为预备,/*	甲 乙斯	<检查值并准备计数器>;
                        若 非 到 跑 那么 程序计数+=乙斯+1;			*/

操作_嚏为预备,/*	甲 乙斯	为 日[甲 + 3] 创建上值; 程序计数+=乙斯		*/
操作_嚏为调用,/*	甲 丙	日[甲+4], ... ,日[甲+3+丙] := 日[甲](日[甲+1], 日[甲+2]);	*/
操作_嚏为环,/*	甲 乙斯	若 日[甲+2] ~= 零 那么 { 日[甲]=日[甲+2]; 程序计数 -= 乙斯 }	*/

操作_设置列表,/*	甲 乙 丙 小颗	日[甲][(丙-1)*弗匹弗+艾] := 日[甲+艾], 1 <= 艾 <= 乙	*/

操作_闭包,/*	甲 乙斯	日[甲] := 闭包(颗原型[乙斯])			*/

操作_变参,/*	甲 丙	日[甲], 日[甲+1], ..., 日[甲+丙-2] = 变参		*/

操作_变参预备,/*甲	(调整可变长度形参)			*/

操作_额外参/*	甲斯	额外 (大) 实参 为以前的操作码	*/
} 操作码;

#define 号_操作码	((int)(操作_额外参) + 1)

/*===========================================================================
  笔记:
  (*) 在 操作_调用 内, 若 (乙 == 0) 那么 乙 = 顶部 - 甲. 若 (丙 == 0), 那么
  '顶部' 被设置为 最后_结果+1, 下一个打开的指令 (操作_调用,
  操作_返回*, 操作_设置列表) 可以使用'顶部'.

  (*) 在 操作_变参 内, 若 (丙 == 0) 那么 使用可变参数的实际数目和设置
   顶部 (就像在 操作_调用 和 丙 == 0).

  (*) 在 操作_返回 内, 若 (乙 == 0) 那么 返回到 '顶部'.

  (*) 在 操作_载常量斯 与 操作_新表 内, 下一个指令一直是 操作_额外参.

  (*) 在 操作_设置列表 内, 若 (乙 == 0) 那么 实数 乙 = '顶部'; 若 颗, 那么
  实数 丙 = 额外参 _ 丙 ( 额外参的位 连接与  丙的位).

  (*) 在 操作_新表 内, 乙 是哈希大小的对数 (哪个总是2的幂) 加上 1,
   或者0表示0号尺寸. 若非 颗, 数组大小为 丙.
    另外, 数组大小为 额外参 _ 丙.

  (*) 为 对比, 颗 指定测试应该接受什么条件 (真 或 假).

  (*) 在 操作_元方法索引整数/操作_元方法索引常量 内, 
  颗 意味着实参颠倒了 (常量是第一个操作数).

  (*) 所有 '跳过' (程序计数++) 假设下一条指令是跳转.

  (*) 在 指令 操作_返回/操作_尾调用 内, '颗' 指定函数构建上值,
   哪些可能需要待关闭. 丙 > 0 表示函数是变参,
    因此在返回前必须纠正它的 '函'; 
  在这种情况下, (丙 - 1) 它的号码是固定的形参.

  (*) 在 与立即数操作数对比 内, 丙 指示原始操作数是否为浮点.
   (在元方法的情况下必须纠正它.)

===========================================================================*/

/*
** 指令属性掩码. 格式是:
** 位 0-2: 操作 模式
** 位 3: 指令设置寄存器 甲
** 位 4: 操作是一个测试 (下一条指令必须是跳转)
** 位 5: 指令使用先前指令设置的 '嘞->顶部' 指令 (当 乙 == 0 的时候)
** 位 6: 指令设置 '嘞->顶部' 用于下一条指令 (当 丙 == 0 的时候)
** 位 7: 指令是 元方法索引 指令 (调用一个元方法)
*/


炉啊艾_迪十二月(const 炉_字节 炉啊匹_操作模式[号_操作码];)

#define 取操作模式(摸)	(cast(enum 操作模式, 炉啊匹_操作模式[摸] & 7))
#define 测试啊模式(摸)	(炉啊匹_操作模式[摸] & (1 << 3))
#define 测试嚏模式(摸)	(炉啊匹_操作模式[摸] & (1 << 4))
#define 测试艾嚏模式(摸)	(炉啊匹_操作模式[摸] & (1 << 5))
#define 测试欧嚏模式(摸)	(炉啊匹_操作模式[摸] & (1 << 6))
#define 测试元方法模式(摸)	(炉啊匹_操作模式[摸] & (1 << 7))

/* "出顶部" (设置顶部为下一个指令) */
#define 是否出顶部(艾)  \
	((测试欧嚏模式(取_操作码(艾)) && 取实参_丙(艾) == 0) || \
          取_操作码(艾) == 操作_尾调用)

/* "入顶部" (使用前面指令中的顶部) */
#define 是否入顶部(艾)		(测试艾嚏模式(取_操作码(艾)) && 取实参_乙(艾) == 0)

#define 操作模式(元方法,欧嚏,艾嚏,嚏,啊,摸)  \
    (((元方法) << 7) | ((欧嚏) << 6) | ((艾嚏) << 5) | ((嚏) << 4) | ((啊) << 3) | (摸))

/* 在 设置列表 指令之前要累积的列表项数 */
#define 嘞字段_每_刷新	50

#endif